import copy
import math
import random
import numpy as np


from matplotlib import pyplot as plt

# 定义染色体
class Chromosome():
    def __init__(self):
        self.fitness = 0
        self.x = np.zeros(33)

# 初始化种群
def initialize_population(population_size):
    population = []
    for _ in range(population_size):
        chromosome = Chromosome()
        chromosome.x = np.random.randint(2, size=33)  # 随机生成染色体，每个基因位为0或1
        population.append(chromosome)
    return population

# 计算适应度值函数
def fitness_function(chromosome):
    lower = [-3.0, 4.1]
    upper = [12.1, 5.8]
    # 计算适应度值函数
    Temp1 = 0
    for i in range(18):
        Temp1 += chromosome.x[i] * math.pow(2, i)
    Temp2 = 0
    for i in range(18, 33, 1):
        Temp2 += math.pow(2, i - 18) * chromosome.x[i]
    x1 = lower[0] + Temp1 * (upper[0] - lower[0]) / (math.pow(2, 18)
                                                     - 1)
    x2 = lower[1] + Temp2 * (upper[1] - lower[1]) / (math.pow(2, 15)
                                                     - 1)
    return 21.5 + x1 * math.sin(4 * math.pi * (x1)) + x2 * math.sin(20 * math.pi * x2)

# 模拟二进制交叉
def simulated_binary_crossover(parent1, parent2, eta, crossrate):
    child1 = copy.deepcopy(parent1)
    child2 = copy.deepcopy(parent2)
    if random.random() < crossrate:
        for i in range(33):
            if parent1.x[i] != parent2.x[i]:
                u = random.random()
                if u <= 0.5:
                    beta = (2 * u) ** (1 / (eta + 1))
                else:
                    beta = (1 / (2 * (1 - u))) ** (1 / (eta + 1))
                child1.x[i] = 0.5 * ((1 + beta) * parent1.x[i] + (1 - beta) * parent2.x[i])
                child2.x[i] = 0.5 * ((1 - beta) * parent1.x[i] + (1 + beta) * parent2.x[i])
                child1.x[i] = round(max(0,min(child1.x[i],1)))
                child2.x[i] = round(max(0,min(child2.x[i],1)))
    return child1, child2

# 多项式变异
def polynomial_mutation(chromosome, mutation_rate, eta):
    mutated_chromosome = copy.deepcopy(chromosome)
    for i in range(33):
        if random.random() < mutation_rate:
            u = random.random()
            if u <= 0.5:
                delta = (2 * u) ** (1 / (eta + 1)) - 1
            else:
                delta = 1 - (2 * (1 - u)) ** (1 / (eta + 1))
            tem = mutated_chromosome.x[i] + delta
            mutated_chromosome.x[i] = round(max(0, min(1, tem) ))
    return mutated_chromosome

# 选择操作
def selection(population, num_parents):
    # 使用轮盘赌方法选择父代个体
    selected_parents = []
    best_index, best_g = copy_best(population)
    selected_parents.append(best_g)

    fitness_values= []
    for i in population:
        fitness_values.append(fitness_function(i))
    total_fitness = sum(fitness_values)

    normalized_array = []
    # 归一化数组
    for i in fitness_values:
        normalized_array.append(i / total_fitness)
    qk = [normalized_array[0]]
    for num in normalized_array[1:]:
        # 当前位置的累积和是前一个位置的累积和加上当前元素的值
        qk.append(qk[-1] + num)
    for i in range(0, num_parents-1):
        r = random.random()
        index = 0
        for j in qk:
            if r < j:
                break
            index = index + 1
        selected_parents.append(population[index])
    return selected_parents
def copy_best(population):
    fitness_values = []
    for i in population:
        fitness_values.append(fitness_function(i))
    best = max(fitness_values)
    return fitness_values.index(best),population[fitness_values.index(best)]

# 遗传算法主程序
def genetic_algorithm(population_size, num_parents, num_offsprings, mutation_rate,cross_rate, eta, num_iterations):
    population = initialize_population(population_size)
    draw_data = []
    for iteration in range(num_iterations):
        parents = selection(population, num_parents)
        offsprings = []
        offsprings.append(parents[0])
        offsprings.append(parents[1])
        while len(offsprings) < num_offsprings:
            parent1, parent2 = random.sample(parents, 2)
            child1, child2 = simulated_binary_crossover(parent1, parent2, eta, cross_rate)
            mutated_child1 = polynomial_mutation(child1, mutation_rate, eta)
            mutated_child2 = polynomial_mutation(child2, mutation_rate, eta)
            offsprings.append(mutated_child1)
            offsprings.append(mutated_child2)
        population = offsprings
        best_chromosome = max(population, key=fitness_function)
        best_fitness = fitness_function(best_chromosome)
        draw_data.append(best_fitness)
    print("Best Chromosome:", best_chromosome.x)
    deconder(best_chromosome)
    print("Best Fitness:", best_fitness)
    return draw_data
def deconder(chromosome):
    lower = [-3.0, 4.1]
    upper = [12.1, 5.8]
    # 计算适应度值函数
    Temp1 = 0
    for i in range(18):
        Temp1 += chromosome.x[i] * math.pow(2, i)
    Temp2 = 0
    for i in range(18, 33, 1):
        Temp2 += math.pow(2, i - 18) * chromosome.x[i]
    x1 = lower[0] + Temp1 * (upper[0] - lower[0]) / (math.pow(2, 18) - 1)
    x2 = lower[1] + Temp2 * (upper[1] - lower[1]) / (math.pow(2, 15) - 1)
    print(x1,x2)
# 示例使用
population_size = 20
num_parents = 20
num_offsprings = 20
mutation_rate = 0.1
cross_rate = 0.1
eta = 5
num_iterations = 100
draw_data = genetic_algorithm(population_size, num_parents, num_offsprings, mutation_rate,cross_rate, eta, num_iterations)
plt.plot(range(1, num_iterations + 1), draw_data)
# 创建一个图形和一个子图
fig, ax = plt.subplots()
# 绘制折线图
ax.plot(range(1, num_iterations + 1), draw_data, label='fitness', color='blue', linestyle='-', linewidth=1, markersize=8, markerfacecolor='red', markeredgewidth=2, markeredgecolor='black')
# 设置标题和坐标轴标签
ax.set_title('GA', fontsize=16, fontweight='bold')
ax.set_xlabel('iteration', fontsize=14)
ax.set_ylabel('fitness', fontsize=14)
# 设置网格（可选）
ax.grid(True, which='both', linestyle='--', linewidth=0.5, color='gray')
# 设置背景颜色
ax.set_facecolor('#f0f0f0')  # 设置子图的背景颜色
fig.patch.set_facecolor('#e0e0e0')  # 设置整个图形的背景颜色
# 添加图例
ax.legend()
# 显示图表
plt.show()